/*
 * mtask.c
 *
 *  Created on: 2016年12月4日
 *      Author: pengzhikang
 */

#include "mtask.h"
#include "timer.h"
#include "naskfunc.h"
#include "dsctbl.h"

struct TIMER *task_timer;
struct TASKCTL *taskctl;

struct TASK *task_now(void) {
	struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv];
	return tl->tasks[tl->now];
}

void task_add(struct TASK *task) {
	struct TASKLEVEL *tl = &taskctl->level[task->level];
	tl->tasks[tl->running] = task;
	tl->running++;
	task->flags = TASK_ACTIVITY;
}

void task_remove(struct TASK *task) {
	int i;
	struct TASKLEVEL *tl = &taskctl->level[task->level];
	// 寻找task所在位置
	for (i = 0; i < tl->running; ++i) {
		if (tl->tasks[i] == task) {
			break;
		}
	}

	tl->running--;
	if (i < tl->now) {
		tl->now--; //需要移动成员，要相应的处理
	}
	if (tl->now >= tl->running) {
		tl->now = 0; // now出现异常则进行修正
	}
	task->flags = TASK_SLEEP;
	// 移动
	for (; i < tl->running; ++i) {
		tl->tasks[i] = tl->tasks[i + 1];
	}
}

void task_switchsub(void) {
	int i;
	for (i = 0; i < MAX_TASKLEVELS; ++i) {
		if (taskctl->level[i].running > 0) {
			break;
		}
	}
	taskctl->now_lv = i;
	taskctl->lv_change = 0; //下次任务切换时不检查LEVEL
}

void task_idle(void) {
	for (;;) {
		io_hlt();
	}
}

struct TASK *task_init(struct MEMMAN *memman) {
	int i;
	struct TASK *task, *idle;
	struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
	taskctl = (struct TASKCTL *) memman_alloc_4k(memman, sizeof(struct TASKCTL));
	for (i = 0; i < MAX_TASKS; i++) {
		taskctl->tasks0[i].flags = TASK_INIT;
		taskctl->tasks0[i].sel = (TASK_GDT0 + i) * 8;
		taskctl->tasks0[i].fifo = 0; // 表示还没有分配字符缓冲区
		taskctl->tasks0[i].tss.ldtr = (TASK_GDT0 + MAX_TASKS + i) * 8;
	}
	for (i = 0; i < MAX_TASKLEVELS; i++) {
		taskctl->level[i].running = 0;
		taskctl->level[i].now = 0;
	}
	task = task_alloc();
	task->flags = TASK_ACTIVITY; //活动中的标志
	task->priority = 2; // 0.02s
	task->level = 0; //最高EVEL
	task_add(task);
	task_switchsub(); // LEVEL设置
	load_tr(task->sel);
	task_timer = timer_alloc();
	timer_settime(task_timer, task->priority);

	idle = task_alloc();
	idle->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;
	idle->tss.eip = (int) &task_idle;
	idle->tss.es = 1 * 8;
	idle->tss.cs = 2 * 8;
	idle->tss.ss = 1 * 8;
	idle->tss.ds = 1 * 8;
	idle->tss.fs = 1 * 8;
	idle->tss.gs = 1 * 8;
	task_run(idle, MAX_TASKLEVELS - 1, 1);
	return task;
}

/**
 * method_point 方法地址
 * parameter 方法参数
 *
 */
struct TASK *task_invoke_method(int method_point, int parameter[]) {
	int i = 0, size = 0;
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	struct TASK *task = task_alloc();
	task->tss.esp = memman_alloc_4k(memman, 64 * 1024) + 64 * 1024;
	task->tss.eip = method_point;
	task->tss.es = 1 * 8;
	task->tss.cs = 2 * 8;
	task->tss.ss = 1 * 8;
	task->tss.ds = 1 * 8;
	task->tss.fs = 1 * 8;
	task->tss.gs = 1 * 8;
	size = sizeof(parameter) / sizeof(int);
	for (i = 0; i < size; ++i) {
		*((int *) (task->tss.esp + (4 * (i + 1)))) = *(i + parameter);
	}
	return task;
}

struct TASK *task_alloc(void) {
	struct MEMMAN *memman = (struct MEMMAN *) MEMMAN_ADDRESS;
	struct SEGMENT_DESCRIPTOR *gdt = (struct SEGMENT_DESCRIPTOR *) ADR_GDT;
	int i;
	struct TASK *task;
	for (i = 0; i < MAX_TASKS; ++i) {
		if (taskctl->tasks0[i].flags == TASK_INIT) {
			task = &taskctl->tasks0[i];
			task->flags = TASK_USE; //正在使用标识
			task->tss.eflags = 0x00000202; //IF =1
			task->tss.eax = 0; /* 设置为0*/
			task->tss.ecx = 0;
			task->tss.edx = 0;
			task->tss.ebx = 0;
			task->tss.ebp = 0;
			task->tss.esi = 0;
			task->tss.edi = 0;
			task->tss.es = 0;
			task->tss.ds = 0;
			task->tss.fs = 0;
			task->tss.gs = 0;
			//task->tss.ldtr = 0;
			task->tss.iomap = 0x40000000;
			task->tss.ss0 = 0; //应用程序没有运行
			if (task->fifo == 0) {
				task->fifo = (struct FIFO32 *) memman_alloc_4k(memman, sizeof(struct FIFO32));
				taskctl->tasks0[i].ldt[0] = (struct SEGMENT_DESCRIPTOR *) memman_alloc_4k(memman, sizeof(struct SEGMENT_DESCRIPTOR));
				taskctl->tasks0[i].ldt[1] = (struct SEGMENT_DESCRIPTOR *) memman_alloc_4k(memman, sizeof(struct SEGMENT_DESCRIPTOR));
				set_segmdesc(gdt + TASK_GDT0 + i, 103, (int) &taskctl->tasks0[i].tss, AR_TSS32);
				set_segmdesc(gdt + TASK_GDT0 + MAX_TASKS + i, 15, (int) *taskctl->tasks0[i].ldt, AR_LDT);
			}
			return task;
		}
	}
	return 0; //全部都在使用
}

void task_run(struct TASK *task, int level, int priority) {
	if (level < 0) {
		level = task->level;
	}
	if (priority > 0) {
		task->priority = priority;
	}
	// 改变活动中的LEVEL
	if (task->flags == TASK_ACTIVITY && task->level != level) {
		//在这里执行之后flag的值会变为1，于是下面的if语句块也会被执行
		task_remove(task);
	}
	if (task->flags != TASK_ACTIVITY) {
		task->level = level;
		task_add(task);
	}

	taskctl->lv_change = 1; //下次任务切换时检查LEVEL
}

void task_sleep(struct TASK *task) {
	struct TASK *now_task;
	if (task->flags == TASK_ACTIVITY) { //活动
		now_task = task_now();
		task_remove(task); //执行此语句的话flags将变成1
		if (task == now_task) {
			task_switchsub();
			now_task = task_now();
			farjmp(0, now_task->sel);
		}
	}
}

void task_switch(void) {
	struct TASKLEVEL *tl = &taskctl->level[taskctl->now_lv];
	struct TASK *new_task, *now_task = tl->tasks[tl->now];

	tl->now++;
	//顺序切换任务，到最后任务时回到最开始的任务
	if (tl->now == tl->running) {
		tl->now = 0;
	}
	// 检查LEVEL
	if (taskctl->lv_change != 0) {
		task_switchsub();
		tl = &taskctl->level[taskctl->now_lv];
	}
	new_task = tl->tasks[tl->now];
	timer_settime(task_timer, new_task->priority);
	if (new_task != now_task) {
		farjmp(0, new_task->sel);
	}
}
